using System;
using System.Collections.Generic;
using System.Text;

namespace WOWEquipOptimizer.Warrior
{
    class Protection : Character
    {
        public Protection()
            : base()
        {
            AllowShield = true;
            m_Base = new List<Attribute>();
            m_Base.Add(new Attribute(AttributeName.Health, 4264));
            m_Base.Add(new Attribute(AttributeName.Stamina, 135));
            m_Base.Add(new Attribute(AttributeName.Strength, 162));
            m_Base.Add(new Attribute(AttributeName.Agility, 93));
            m_Base.Add(new Attribute(AttributeName.ParryRating, 5 * ParryRating));
            m_Base.Add(new Attribute(AttributeName.BlockRating, 5 * BlockRating));
            m_Base.Add(new Attribute(AttributeName.DodgeRating, 0.758f * DodgeRating));
            m_Base.Add(new Attribute(AttributeName.DefenseRating, 20 * DefenseSkillRating));
            m_Base.Add(new Attribute(AttributeName.BlockRating, 5 * BlockRating));
            m_Base.Add(new Attribute(AttributeName.ParryRating, 5 * ParryRating));
            foreach (Attribute attr in m_Base)
            {
                handleAttribute(attr);
            }
            m_Equip[AttributeName.DefenseRating] += 350 * DefenseSkillRating; // workaround since the base defskill does not raise dodge etc.
            Buff comshout = new Buff("Commanding Shout", new List<Attribute>());
            comshout.Attributes.Add(new Attribute(AttributeName.Health, 1080));
            Buffs.Add(comshout);
            Buff crawdad = new Buff("Spicy Crawdad", new List<Attribute>());
            crawdad.Attributes.Add(new Attribute(AttributeName.Stamina, 30));
            crawdad.Attributes.Add(new Attribute(AttributeName.Spirit, 20));
            Buffs.Add(crawdad);
            Buff fortification = new Buff("Flask of Fortification", new List<Attribute>());
            fortification.Attributes.Add(new Attribute(AttributeName.Health, 500));
            fortification.Attributes.Add(new Attribute(AttributeName.DefenseRating, 10));
            Buffs.Add(fortification);
            Buff bloodpact = new Buff("Blood Pact", new List<Attribute>());
            bloodpact.Attributes.Add(new Attribute(AttributeName.Stamina, 70 * 1.3f));
            Buffs.Add(bloodpact);
            GoodAttributes.Add(AttributeName.Stamina);
            GoodAttributes.Add(AttributeName.Health);
        }
        public override void evaluateItem(Item item, int slot)
        {
            base.evaluateItem(item, slot);
            m_Equip[AttributeName.Armor] += item.Armor;
        }
        // "Health", "Stamina", "Strength", "Agility", "Armor", "DefenseRating", "DodgeRating", "BlockRating", "ParryRating", "BlockValue" 
        public override void handleAttribute(Attribute attr)
        {
            switch (attr.Type)
            {
                case AttributeName.Armor:
                    m_Equip[attr.Type] += attr.Value * 1.1f;
                    break;
                case AttributeName.Agility:
                    m_Equip[attr.Type] += attr.Value * (HasBlessingOfKings ? 1.1f : 1.0f);
                    m_Equip[AttributeName.Armor] += attr.Value * (HasBlessingOfKings ? 1.1f : 1.0f) * 2;
                    m_Equip[AttributeName.DodgeRating] += (attr.Value * (HasBlessingOfKings ? 1.1f : 1.0f) / 30f) * DodgeRating;
                    break;
                case AttributeName.BlockValue:
                    m_Equip[attr.Type] += attr.Value * 1.3f;
                    break;
                case AttributeName.DefenseRating:
                    m_Equip[attr.Type] += attr.Value;
                    m_Equip[AttributeName.DodgeRating] += (attr.Value / DefenseSkillRating) * 0.04f * DodgeRating;
                    m_Equip[AttributeName.BlockRating] += (attr.Value / DefenseSkillRating) * 0.04f * BlockRating;
                    m_Equip[AttributeName.ParryRating] += (attr.Value / DefenseSkillRating) * 0.04f * ParryRating;
                    break;
                case AttributeName.Stamina:
                    m_Equip[AttributeName.Health] += attr.Value * 10 * (HasBlessingOfKings ? 1.1f : 1.0f) * 1.05f;
                    m_Equip[attr.Type] += attr.Value * (HasBlessingOfKings ? 1.1f : 1.0f) * 1.05f;
                    break;
                case AttributeName.Strength:
                    m_Equip[attr.Type] += attr.Value * (HasBlessingOfKings ? 1.1f : 1.0f) * 1.10f;
                    m_Equip[AttributeName.BlockValue] += attr.Value * (HasBlessingOfKings ? 1.1f : 1.0f) * 1.10f / 20f;
                    break;
                default:
                    base.handleAttribute(attr);
                    break;
            }
        }

        public override bool evaluateBuild(int[] build)
        {
            if (build[2] >= 41)
            {
                return true;
            }
            else return false;
        }
        public override List<Item> filterEquip(List<Item> input)
        {
            input = base.filterEquip(input);
            List<Item> retval = new List<Item>();
            foreach (Item item in input)
            {
                if ((item.AllowableClasses & CharacterClass.Warrior) == 0) continue;
                else if (item.GetType() == typeof(Armor))
                {
                    Armor armor = (Armor)item;
                    if ((armor.Type & ArmorProficiency.Plate) == 0 && armor.Type != ArmorProficiency.Shield) continue;
                    if (armor.Slot == ArmorSlot.OffHand) continue;
                }
                else if (item.GetType() == typeof(Weapon))
                {
                    Weapon weapon = (Weapon)item;
                    if (weapon.TwoHand) continue;
                    if (weapon.WeaponSlot == WeaponSlot.OffHand) continue;
                }
                if (SetBlacklist.Contains(item.Set.Name)) continue;
                if (ItemBlacklist.Contains(item.Name)) continue;
                bool bad = false;
                foreach (Attribute attr in item.Attributes)
                {
                    switch (attr.Type)
                    {
                        case AttributeName.SpellDamage:
                        case AttributeName.HitSpellRating:
                        case AttributeName.CritSpellRating:
                        case AttributeName.CritMeleeRating:
                        case AttributeName.CritRating:
                        case AttributeName.Mana:
                        case AttributeName.Intellect:
                        case AttributeName.Spirit:
                        case AttributeName.MP5:
                        case AttributeName.Healing:
                            {
                                bad = true;
                                break;
                            }
                        default:
                            break;
                    }
                }
                if (!bad)
                {
                    retval.Add(item);
                }
            }
            return handleWhiteList(retval);
        }
        // "Health", "Stamina", "Strength", "Agility", "Armor", "DefenseRating", "DodgeRating", "BlockRating", "ParryRating", "BlockValue" 
        public override float evaluateTF()
        {
            float health = m_Equip[AttributeName.Health];
            float strength = m_Equip[AttributeName.Strength];
            float armor = m_Equip[AttributeName.Armor];
            float defskill = m_Equip[AttributeName.DefenseRating] / DefenseSkillRating;
            float dodge = m_Equip[AttributeName.DodgeRating] / DodgeRating - 0.6f;
            float block = m_Equip[AttributeName.BlockRating] / BlockRating - 0.6f;
            float parry = m_Equip[AttributeName.ParryRating] / ParryRating - 0.6f;
            float blockvalue = m_Equip[AttributeName.BlockValue] - 1;
            float misschance = (5 + (defskill-365) * 0.04f);
            float mobhitspeed = 1.5f;
            float mobdmg = 12000;
            float reduce = 1 - Math.Min((armor / (armor + 11960f)), 0.75f); // 11960 is apparently the correct value vs. lvl 73
            float avoidance = Math.Min((dodge + parry + misschance), 100); // artitifical stop, otherwise you get too much defgear
            float crushchance = 15;
            float shieldblockuptime = Math.Min(((mobhitspeed * 2) / 6f) / (1 - avoidance / 100),1);
            float crithitchance = Math.Max((490 - defskill) * 0.04f, 0);
            float blockchance = Math.Min(block + shieldblockuptime * 75,100);
            // simplify(((1-avoidance) *((1-blockvalue)*block/(1-avoidance) + 2*crit/(1-avoidance) + 1.5*crush/(1-avoidance) + (1-avoidance-block-crit-crush)/(1-avoidance))));
            // -blockvalue*block + crit + 0.5000000000 crush + 1. - 1. avoidance
            float basedmg = reduce * mobdmg * 0.9f; //incl. def stance
            // blockeddmg is basically the percentage of blocked dmg compared to normal dmg
            float blockeddmg = (1 - ((basedmg - blockvalue) / basedmg)) * blockchance;
            float finaldmg = Math.Max((crithitchance + 0.5f * crushchance + 100 - avoidance - blockeddmg) * 1 / 100f * basedmg, 1);
            float magicaldmg = 5000 * 0.9f * 0.9f;
            return CondFactor*health / (finaldmg + magicaldmg);
        }
        public override string[] getAttributes()
        {
            return new string[] { "Health", "Stamina", "Strength", "Agility", "Armor", "DefenseRating", "DodgeRating", "BlockRating", "ParryRating", "BlockValue" };
        }
        public override int getAttributesEnd()
        {
            return this.getAttributes().Length;
        }
        public override string targetValue()
        {
            return "SPH";
        }
    }
}
